import anime from "animejs"


interface MyCanvasOption {
  canvasDom: HTMLCanvasElement;
  width: number;
  height: number;
}

interface ItemNode {
  name:string;
  color:string;
  position:{x:number,y:number};
  rotation:number;
  width:number;
  height:number;
  parent:ItemNode|null;
  children:ItemNode[];
}

class MyCanvas {

  canvasDom: HTMLCanvasElement;
  canvasCtx: CanvasRenderingContext2D | null;
  width: number;
  height: number;

  audioDom: HTMLAudioElement;
  audioCtx: AudioContext;
  anlyser: AnalyserNode;
  source: MediaElementAudioSourceNode | null = null;

  nodeList:ItemNode[] = []

  constructor(option: MyCanvasOption) {
    this.canvasDom = option.canvasDom;
    this.canvasCtx = this.canvasDom.getContext('2d');
    this.width = option.width;
    this.height = option.height;


    let world:ItemNode = {
      name:"world",
      color:"#0000ff00",
      position:{x:0,y:0},
      rotation:0,
      width:this.width,
      height:this.height,
      parent:null,
      children:[]
    }

    let test_node1:ItemNode = {
      name:"test_node1",
      color:"#ffffff00",
      position:{x:0,y:0},
      rotation:0,
      width:10,
      height:300,
      parent:world,
      children:[]
    }

    let test_node2:ItemNode = {
      name:"test_node2",
      color:"#0000ff",
      position:{x:0,y:-150},
      rotation:0,
      width:40,
      height:10,
      parent:test_node1,
      children:[]
    }
    test_node1.children.push(test_node2)
    world.children.push(test_node1)

    this.nodeList.push(world)
    console.log(this.nodeList)
  }

  conectFile(audioDom: HTMLAudioElement) {
    this.audioCtx = new AudioContext();
    this.anlyser = this.audioCtx.createAnalyser();
    this.audioDom = audioDom;
    this.source = this.audioCtx.createMediaElementSource(this.audioDom);
    this.source?.connect(this.anlyser);
    this.source?.connect(this.audioCtx.destination);
  }


  startAnime(){

    let target = {
      angle:0
    }

    anime({
      targets:target,
      angle:360,
      duration:300,
      easing:"linear",
      loop:true,
      update:()=>{
        this.nodeList[0].children[0].rotation = target.angle
      }
    })

  }

  changeNodeList(v:number){
    this.nodeList[0].children[0].children[0].position.y = -150*v
  }

  init() {

    this.drawNodeList(this.nodeList,{x:this.width/2,y:this.height/2},0)

  }


  drawNodeList(nodeList:ItemNode[],origin:{x:number,y:number},rotation:number){

    nodeList.forEach((node)=>{
      
      this.drawNode(node,origin,rotation)

      if (node.children.length>0) {
        let node_origin = {x:node.position.x+origin.x,y:node.position.y+origin.y}
        let node_rotation = node.rotation+rotation
        this.drawNodeList(node.children,node_origin,node_rotation)
        
      }
      
    })

  }

  drawNode(node:ItemNode,origin:{x:number,y:number},rotation:number){
    if(this.canvasCtx){

      this.canvasCtx.save()
      //移动画布坐标系 到父级坐标系
      this.canvasCtx.translate(origin.x,origin.y)
      this.canvasCtx.rotate(rotation*Math.PI/180)
      //移动画布坐标系 到自身坐标
      this.canvasCtx.translate(node.position.x,node.position.y)
      this.canvasCtx.rotate(node.rotation*Math.PI/180)

      this.canvasCtx.fillStyle = node.color;
      this.canvasCtx.fillRect(-node.width/2, -node.height/2, node.width, node.height);
      this.canvasCtx.restore()

    }
  }



  update = () => {
    requestAnimationFrame(this.update); 
    this.canvasCtx.clearRect(0, 0, this.width, this.height);
    if (this.source) {
      this.drawMusicLine()
    }
    this.drawNodeList(this.nodeList,{x:this.width/2,y:this.height/2},0)
  }


  drawMusicLine() {

    let analyser = this.anlyser;
    analyser.fftSize = 128;
    const bufferLength = analyser.fftSize
    const dataArray = new Uint8Array(bufferLength);

    analyser.getByteTimeDomainData(dataArray);
    // console.log(dataArray)

    const canvasCtx = this.canvasCtx;
    if (!canvasCtx) {
      return
    }
    canvasCtx.fillStyle = "rgb(200, 200, 200)";
    canvasCtx.fillRect(0, 0, this.width, this.height);

    canvasCtx.lineWidth = 2;
    canvasCtx.strokeStyle = "rgb(0, 0, 0)";

    canvasCtx.beginPath();

    const sliceWidth = (this.width * 1.0) / bufferLength;
    let x = 0;

    for (let i = 0; i < bufferLength; i++) {

      const v = dataArray[i] / 128.0;
      this.changeNodeList(v)

      const y = (v * this.height) / 2;

      if (i === 0) {
        canvasCtx.moveTo(x, y);
      } else {
        canvasCtx.lineTo(x, y);
      }

      x += sliceWidth;
    }

    canvasCtx.lineTo(this.width, this.height / 2);
    canvasCtx.stroke();


  }

}

export default MyCanvas
